﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
using System.Collections;
using System.Windows.Forms;
using CalcEng;

namespace CSKB
{
    class KeyOperation
    {
        public int m_sleeptime;
        public int m_msgtype;
        public int m_key;
    }

    class StockItem
    {
        public string code;
        public float vol;
       /* public float yclose;
        public float open;
        public float close;
        public float amount;
        public float high;
        public float low;*/
    }

    class KeyBoardPlayer
    {
        const int BN_OK = 0x0001;
        const int BN_CANCEL = 0x0002;
        const int EN_EDIT = 0X0563;
        const int TB1_CTRL = 0x80BA;
        const int MAX_DOWNLOAD_TIMES = 10;

        IntPtr m_TargetMainWnd;
        IntPtr m_TargetWnd;
        int    m_TargetThreadId;
        int    m_TargetPid;
        int    m_SelfPid;
        string m_stolistFile;
        string m_sTdxPath;
        bool   m_bCalc;
        bool   m_bNote;
        bool   m_bHtml;
        public StreamWriter m_sw;
        float  m_speed;
        int m_iCheckExistence;

        public IntPtr TargetMainWnd
        {
            get { return m_TargetMainWnd; }
        }

        public int CheckExistence
        {
            set { m_iCheckExistence = value; }
        }

        private void PrePlay()
        {
            int curentThreadId = Win32API.GetCurrentThreadId();
            int iret = Win32API.AttachThreadInput(m_TargetThreadId, curentThreadId, true);
            /*if(iret == 0)
                iret = Marshal.GetLastWin32Error();*/
            bool bret = Win32API.SetForegroundWindow(m_TargetMainWnd);            

            if (m_bCalc && m_sw == null)
            {
                string ofilename = m_stolistFile.Replace(".xls", @"output.xls");
                m_sw = new StreamWriter(ofilename, false, System.Text.Encoding.Default);
                CalcEngine.FormatOutfileHead(m_sw);
            }

            //System.Threading.Thread.Sleep(200);
            Win32API.SetFocus(m_TargetWnd);
        }

        private void PostPlay()
        {
            int curentThreadId = Win32API.GetCurrentThreadId();
            int iret = Win32API.AttachThreadInput(m_TargetThreadId, curentThreadId, false);
      
            if ( m_sw != null)
            {
                m_sw.Close();
                m_sw = null;
            }
        }


        private List<KeyOperation> ReadKeySequence()
        {
            string filename = Path.GetFullPath(
                                  System.Windows.Forms.Application.ExecutablePath).Replace(".exe", ".txt");
            List<KeyOperation> arr = new List<KeyOperation>();
            using (StreamReader sr = new StreamReader(filename))
            {
                string line = sr.ReadLine();
                line = sr.ReadLine();
                while (line != null)
                {
                    string[] words = line.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries);

                    KeyOperation ko = new KeyOperation();
                    int.TryParse(words[1], out ko.m_sleeptime);
                    int.TryParse(words[3], out ko.m_key);

                    switch (words[2])
                    {
                        case "u":
                            ko.m_msgtype = Win32API.WM_IME_KEYUP;
                            break;
                        case "d":
                            ko.m_msgtype = Win32API.WM_IME_KEYDOWN;
                            break;
                        case "c":
                            ko.m_msgtype = Win32API.WM_IME_CHAR;
                            break;
                    }

                    arr.Add(ko);
                    line = sr.ReadLine();
                }
            }
            return arr;
        }

        public string StoListFilePath
        {
            set { m_stolistFile = value; }
            get { return m_stolistFile; }
        }

        public int Speed
        {
            set 
            {
                float ratio = (200 - value) / 100.0F;
                m_speed = ratio*ratio;
            }
            //get { return 100 - m_speed; }
        }

        public KeyBoardPlayer(int targetPid, bool bCalc, bool bNote, bool bHtml, int CheckExistence)
        {
            m_bCalc = bCalc;
            m_bNote = bNote;
            m_bHtml = bHtml;
            m_iCheckExistence = CheckExistence;
            m_sw = null;
            Initialize(targetPid);
        }

        private List<CalcResult> DownloadData(ref List<StockItem> stockItems, List<KeyOperation> keyOps, StockItem lastItem, int times)
        {
            List<CalcResult> cRets = new List<CalcResult>();      
            IntPtr focusedWnd = CheckFocusedWnd();
            string outdir = Path.GetDirectoryName(m_stolistFile) + @"\";
           
            string lastCode = null;
            int lastIndex = int.MaxValue;
            int curIndex = stockItems.Count() - 1;
            if (lastItem != null)
            {
                lastCode = lastItem.code;
                lastIndex = stockItems.IndexOf(lastItem);
                curIndex = lastIndex - 1;
            }

            for (; curIndex >= 0; curIndex--)
            {
                StockItem sitem = stockItems.ElementAt(curIndex);
                string code = sitem.code;
                foreach (char ch in code)
                {
                    System.Threading.Thread.Sleep(30);
                    focusedWnd = CheckFocusedWnd();
                    Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, (int)ch, 0);
                }

                foreach (KeyOperation op in keyOps)
                {
                    System.Threading.Thread.Sleep(op.m_sleeptime);
                    if (op.m_msgtype != Win32API.WM_IME_KEYUP)
                    {
                        focusedWnd = CheckFocusedWnd();
                    }
                    Win32API.SendMessage(focusedWnd, op.m_msgtype, op.m_key, 0);
                }

                System.Threading.Thread.Sleep(80);
                focusedWnd = CheckFocusedWnd();
                focusedWnd = Win32API.GetParent(focusedWnd);
                Win32API.SendMessage(focusedWnd, Win32API.WM_COMMAND,
                                        BN_OK,
                                        Win32API.GetDlgItem(focusedWnd, BN_OK).ToInt32());

                int waitms = (int)((sitem.vol / 1.60F) * m_speed)*times;
                waitms = Math.Max(666, waitms);
                System.Threading.Thread.Sleep(waitms);

                if (lastIndex < int.MaxValue)
                {
                    if (CheckFileExistence(outdir, lastCode))
                    {
                        stockItems.RemoveAt(lastIndex);
                        if (m_bCalc)
                        {
                            CalcPara cp = new CalcPara();
                            cp.filename = outdir + lastCode + ".XLS";
                            cp.outstream = m_sw;
                            cp.code = lastCode;
                            CalcResult cret = CalcEngine.Calc(cp);
                            if (cret != null)
                            {
                                cRets.Add(cret);
                                if (m_bHtml)
                                {
                                    HtmlEngine.UpdateHtml(m_sTdxPath, cret);
                                }
                            }
                        }
                    }
                }
                lastCode = code;
                lastIndex = curIndex;

                focusedWnd = CheckFocusedWnd();
                focusedWnd = Win32API.GetParent(focusedWnd);
                Win32API.SendMessage(focusedWnd, Win32API.WM_COMMAND,
                                        BN_CANCEL,
                                        Win32API.GetDlgItem(focusedWnd, BN_CANCEL).ToInt32());
            }

            if (lastIndex < int.MaxValue)
            {
                if (CheckFileExistence(outdir, lastCode))
                {
                    stockItems.RemoveAt(lastIndex);
                    if (m_bCalc)
                    {
                        CalcPara cp = new CalcPara();
                        cp.filename = outdir + lastCode + ".XLS";
                        cp.outstream = m_sw;
                        cp.code = lastCode;
                        CalcResult cret = CalcEngine.Calc(cp);
                        if (cret != null)
                        {
                            cRets.Add(cret);
                            if (m_bHtml)
                            {
                                HtmlEngine.UpdateHtml(m_sTdxPath, cret);
                            }
                        }
                    }
                }
            }

            return cRets;
        }


        public void Play()
        {
            System.DateTime dtstart = System.DateTime.Now;

            PrePlay();

            string strComplete;
            List<StockItem> stockItems = GetStockItems();
            int cntToDownload = stockItems.Count();
            if (cntToDownload > 0)
            {
                StockItem sitem = stockItems.ElementAt(cntToDownload - 1);
                string lastCode = GetFirstData(sitem);        //to init the output folder path
                List<KeyOperation> keyOps = ReadKeySequence();

                int times = 1;
                List<CalcResult> allCrets = DownloadData(ref stockItems, keyOps, sitem, times);

                if (m_iCheckExistence < 2)
                {
                    while (stockItems.Count() > 0 && times++ < 6)
                    {
                        List<CalcResult> crets = DownloadData(ref stockItems, keyOps, null, times);
                        allCrets.AddRange(crets);
                    }
                }

                if (allCrets.Count() > 0)
                {
                    if (m_bNote)
                    {
                        string blockName = Path.GetFileNameWithoutExtension(m_stolistFile);
                        BlockNew.WriteToBlocks(blockName, m_sTdxPath, allCrets);
                    }
/*
                    if (m_bHtml)
                    {
                        HtmlEngine.UpdateHtmls(m_sTdxPath, allCrets);
                    }*/
                }

                System.TimeSpan ts = System.DateTime.Now - dtstart;

                if (m_iCheckExistence < 2)
                    strComplete = string.Format("Downloaded {0} of {1} items by {2} times within {3}H{4}M{5}S",
                                                  cntToDownload - stockItems.Count(), cntToDownload, times, ts.Hours, ts.Minutes, ts.Seconds);
                else
                    strComplete = "Download data Completed"+ts.ToString();
            }
            else
            {
                strComplete = "No data need to download";
            }

            PostPlay();

            IntPtr mainWnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
            Win32API.SetForegroundWindow(mainWnd);
            Win32API.MessageBox(mainWnd, strComplete, null, 0);
        }

        private List<StockItem> GetStockItems()
        {
            StreamReader sr = new StreamReader(m_stolistFile);
            List<StockItem> stockItems = new List<StockItem>();
         
            sr.ReadLine();//skip 1st row
            m_sTdxPath = sr.ReadLine().TrimEnd(null);
            sr.ReadLine();//skip 3rd row, headers

            if (m_bHtml)
            {
                string htmlFolder = m_sTdxPath + @"\T0002\export\HTMLs\";
                if (!Directory.Exists(htmlFolder))
                {
                    Directory.CreateDirectory(htmlFolder);
                }
            }

            string outdir = Path.GetDirectoryName(m_stolistFile) + @"\";

            string line = sr.ReadLine();
            while (line != null)
            {
                string[] words = line.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries);
                if (words[0].StartsWith("00") || words[0].StartsWith("300"))
                {                     
                    if (!CheckFileExistence(outdir, words[0]))
                    {
                        StockItem sitem = new StockItem();
                        sitem.code = words[0];
                        float vol = 3000 * 1.68F;
                        float.TryParse(words[1], out vol);
                        sitem.vol = vol;
                        stockItems.Add(sitem);
                    }
                }
                line = sr.ReadLine();
            }
            sr.Close();
            return stockItems;
        }

        private bool CheckFileExistence(string outdir, string code)
        {
            bool bRet = false;

            if (m_iCheckExistence < 2)
            {
                string filename = outdir + code + ".XLS";
                if (File.Exists(filename))
                {
                    if (m_iCheckExistence < 1)
                    {
                       // try
                        {
                            FileInfo fi = new FileInfo(filename);
                          
                            if (  fi.LastWriteTime.Hour >= 15 ||
                                  (fi.LastWriteTime.Hour < 9) ||
                                  fi.LastWriteTime.DayOfWeek == DayOfWeek.Sunday ||
                                  fi.LastWriteTime.DayOfWeek == DayOfWeek.Saturday)
                            {
                                bRet = true;
                            }
                            /*else
                            {
                                fi.Delete();
                            }*/
                        }
                      //  catch (Exception e)
                        {
                     //       Console.WriteLine("The process failed: {0}", e.ToString());
                        }
                    }
                    else
                    {
                        bRet = true;
                    }

                 /*   if (bRet && m_bCalc)
                    {
                        CalcPara cp = new CalcPara();
                        cp.filename = filename;
                        cp.outstream = m_sw;
                        cp.code = code;
                        CalcResult cret = CalcEngine.Calc(cp);
                        if (cret != null && m_bHtml)
                        {
                            HtmlEngine.UpdateHtml(m_sTdxPath, cret);
                        }
                    }*/
                }
            }
            return bRet;
        }

        private IntPtr CheckFocusedWnd()
        {
            IntPtr fWnd = Win32API.GetFocus();
            int cnt = 0;
            int wdpid;
            Win32API.GetWindowThreadProcessId(fWnd, out wdpid);
            while (wdpid != m_TargetPid)
            {
                
                if (cnt > 35)
                {
                    Win32API.SetForegroundWindow(m_TargetMainWnd);
                    System.Threading.Thread.Sleep(200);
                    //IntPtr ipRet = Win32API.SetFocus(m_TargetWnd);
                    cnt = 0;
                }
                System.Threading.Thread.Sleep(300);
                
                Monitor.Enter(this);
                fWnd = Win32API.GetFocus();
                Monitor.Exit(this);

                Win32API.GetWindowThreadProcessId(fWnd, out wdpid);
                if (m_SelfPid != wdpid)
                {  //cskb form is not the top window
                    cnt++;
                }
            }
            //Console.WriteLine("Focused Wnd " + fWnd.ToInt32().ToString());       
            return fWnd;
        }
        
        private string GetFirstData(StockItem sitem)
        {
            IntPtr focusedWnd;
            string code = sitem.code;         
            foreach (char ch in code)
            {
                focusedWnd = CheckFocusedWnd();
                Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, (int)ch, 0);
                System.Threading.Thread.Sleep(60);
            }
            //return
            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_KEYDOWN, 13, 0);
            System.Threading.Thread.Sleep(66);
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_KEYUP, 13, 0);
            System.Threading.Thread.Sleep(999);
            
            //.501
            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, 46, 0);
            System.Threading.Thread.Sleep(80);
            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, 53, 0);
            System.Threading.Thread.Sleep(80);
            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, 48, 0);
            System.Threading.Thread.Sleep(80);
            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, 49, 0);
            System.Threading.Thread.Sleep(80);

            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_KEYDOWN, 13, 0);
            System.Threading.Thread.Sleep(80);
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_KEYUP, 13, 0);
            System.Threading.Thread.Sleep(200);

            //01
            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, 48, 0);
            System.Threading.Thread.Sleep(80);
            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, 49, 0);
            System.Threading.Thread.Sleep(80);

            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_KEYDOWN, 13, 0);
            System.Threading.Thread.Sleep(80);
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_KEYUP, 13, 0);
            System.Threading.Thread.Sleep(200);

            //34
            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, 51, 0);
            System.Threading.Thread.Sleep(80);

            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_CHAR, 52, 0);
            System.Threading.Thread.Sleep(80);

            focusedWnd = CheckFocusedWnd();
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_KEYDOWN, 13, 0);
            System.Threading.Thread.Sleep(80);
            Win32API.SendMessage(focusedWnd, Win32API.WM_IME_KEYUP, 13, 0);
            System.Threading.Thread.Sleep(200);
                                      
            focusedWnd = CheckFocusedWnd();
            focusedWnd = Win32API.GetParent(focusedWnd);
            Win32API.SendDlgItemMessage(focusedWnd, TB1_CTRL, Win32API.WM_LBUTTONDOWN, 1, 0X00070080);
            System.Threading.Thread.Sleep(30);
            Win32API.SendDlgItemMessage(focusedWnd, TB1_CTRL, Win32API.WM_LBUTTONUP, 0, 0X00070080);

            string outputfile = Path.GetDirectoryName(m_stolistFile) + @"\" + code + ".XLS";
            IntPtr hEdit = Win32API.GetDlgItem(focusedWnd, EN_EDIT);
            Win32API.SetFocus(hEdit);
            Win32API.SendDlgItemMessage(focusedWnd, EN_EDIT, Win32API.EM_SETSEL, 0, -1);
            foreach (char ch in outputfile)
            {
                Win32API.SendMessage(hEdit, Win32API.WM_IME_CHAR, (int)ch, 0);
                System.Threading.Thread.Sleep(20);
            }
           /* Win32API.SetWindowText(hEdit, outputfile);
            Win32API.SendMessage(focusedWnd, Win32API.WM_COMMAND, Win32API.EN_UPDAT | EN_EDIT, hEdit.ToInt32());
            Win32API.SendMessage(focusedWnd, Win32API.WM_COMMAND, Win32API.EN_CHANGE | EN_EDIT, hEdit.ToInt32());
            */
            Win32API.SendMessage(focusedWnd, Win32API.WM_COMMAND,
                                  BN_OK,
                                  Win32API.GetDlgItem(focusedWnd, BN_OK).ToInt32());
            System.Threading.Thread.Sleep(3000);

            focusedWnd = CheckFocusedWnd();
            focusedWnd = Win32API.GetParent(focusedWnd);
            Win32API.SendMessage(focusedWnd, Win32API.WM_COMMAND,
                                 BN_CANCEL,
                                 Win32API.GetDlgItem(focusedWnd, BN_CANCEL).ToInt32());
            return code;
        }

        private void Initialize(int targetPid)
        {
            m_TargetWnd = IntPtr.Zero;
            m_TargetMainWnd = IntPtr.Zero;
            m_SelfPid = Win32API.GetCurrentProcessId();

            while(true)
	        {
                m_TargetMainWnd = Win32API.FindWindowEx(IntPtr.Zero, m_TargetMainWnd, "TdxW_MainFrame_Class", null);
                if (IntPtr.Zero == m_TargetMainWnd)
		        {
                    System.Windows.Forms.MessageBox.Show("Find TdxW_MainFrame_Class Window failed");
			        break;
		        }
		        int wdpid;
                m_TargetThreadId = Win32API.GetWindowThreadProcessId(m_TargetMainWnd, out wdpid);
                if (targetPid == 0 || wdpid == targetPid)
		        {
                    m_TargetPid = wdpid;

                    m_TargetWnd = Win32API.FindWindowEx(m_TargetMainWnd, m_TargetWnd, "MDIClient", null);
				    if(IntPtr.Zero == m_TargetWnd)
				    {
					    System.Windows.Forms.MessageBox.Show("Find MDIClient Window Failed");
				    }
				    else
				    {
					    //AttachThreadInput(dwThread, GetCurrentThreadId(), TRUE);   
				    }			        
			        break;
                }
		    }
	    }

    }
}
